/*
 * FreeRTOS Kernel <DEVELOPMENT BRANCH>
 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * SPDX-License-Identifier: MIT
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * https://www.FreeRTOS.org
 * https://github.com/FreeRTOS
 *
 */

/* tos secure context includes. */
#include "tos_secure_context.h"

/* tos secure port macros. */
#include "tos_secure_port_macros.h"

void tos_secure_load_ctx_asm( k_secure_ctx_t * task_secure_context ) __attribute__( ( naked ) );
void tos_secure_save_ctx_asm( k_secure_ctx_t * task_secure_context ) __attribute__( ( naked ) );

void tos_secure_load_ctx_asm( k_secure_ctx_t * task_secure_context )
{
    /* task_secure_context value is in r0. */
    __asm volatile
    (
        " .SYNTAX UNIFIED                  \n\t"
        "                                   \n\t"
        " MRS R1, IPSR                     \n\t" /* R1 = IPSR. */
        " CBZ R1, load_ctx_thread_mode      \n\t" /* Do nothing if the processor is running in the Thread Mode. */
        " LDMIA R0!, {R1, R2}              \n\t" /* R1 = task_secure_context->curr_psp, R2 = task_secure_context->psp_limit. */
        "                                   \n\t"
        #if ( __MPU_PRESENT == 1 )
            " LDMIA R1!, {R3}                \n\t" /* Read CONTROL register value from task's stack. R3 = CONTROL. */
            " MSR CONTROL, R3                \n\t" /* CONTROL = R3. */
        #endif /* configENABLE_MPU */
        "                                   \n\t"
        " MSR PSPLIM, R2                   \n\t" /* PSPLIM = R2. */
        " MSR PSP, R1                      \n\t" /* PSP = R1. */
        "                                   \n\t"
        " load_ctx_thread_mode:            \n\t"
        "    BX LR                         \n\t"
        "                                   \n\t"
    );
}
/*-----------------------------------------------------------*/

void tos_secure_save_ctx_asm( k_secure_ctx_t * task_secure_context )
{
    /* task_secure_context value is in r0. */
    __asm volatile
    (
        " .SYNTAX UNIFIED                  \n\t"
        "                                  \n\t"
        " MRS R1, IPSR                     \n\t" /* R1 = IPSR. */
        " CBZ R1, save_ctx_thread_mode     \n\t" /* Do nothing if the processor is running in the Thread Mode. */
        " MRS R1, PSP                      \n\t" /* R1 = PSP. */
        #if ( ( __FPU_PRESENT == 1) || ( configENABLE_MVE == 1 ) )
            " VSTMDB R1!, {S0}               \n\t" /* Trigger the deferred stacking of FPU registers. */
            " VLDMIA R1!, {S0}               \n\t" /* Nullify the effect of the previous statement. */
        #endif /* configENABLE_FPU || configENABLE_MVE */
        #if ( __MPU_PRESENT == 1)
            " MRS R2, CONTROL                 \n\t" /* R2 = CONTROL. */
            " STMDB R1!, {R2}                 \n\t" /* Store CONTROL value on the stack. */
        #endif /* configENABLE_MPU */
        " STR R1, [R0]                     \n\t" /* Save the top of stack in context. task_secure_context->curr_psp = R1. */
        " MOVS R1, #0                      \n\t" /* R1 = K_SECURE_CTX_NO_STACK. */
        " MSR PSPLIM, R1                   \n\t" /* PSPLIM = K_SECURE_CTX_NO_STACK. */
        " MSR PSP, R1                      \n\t" /* PSP = K_SECURE_CTX_NO_STACK i.e. No stack for thread mode until next task's context is loaded. */
        "                                  \n\t"
        " save_ctx_thread_mode:            \n\t"
        "    BX LR                         \n\t"
        "                                  \n\t"
    );
}
/*-----------------------------------------------------------*/
